#include <errno.h>
#include <fcntl.h>
#include <libdrm/drm_mode.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <xf86drm.h>
#include <xf86drmMode.h>

#define BUFFER_SIZE 1920 * 1080 * 4 // assuming 32 bits per pixel

int main(int argc, char *argv[])
{
    int fd, ret, i;
    drmModeRes *res;
    drmModeConnector *conn;
    drmModeEncoder *enc;
    drmModeCrtc *crtc;
    drmModeModeInfo mode;
    uint32_t *image_buffer;
    uint32_t image_pitch;
    uint32_t image_size;
    uint32_t connector_id, crtc_id, encoder_id;

    // Open the DRM device file
    fd = open("/dev/dri/card0", O_RDWR);
    if (fd < 0) {
        fprintf(stderr, "Error opening DRM device: %s\n", strerror(errno));
        return 1;
    }

    // Get the list of connectors and find one that is connected and has modes
    res = drmModeGetResources(fd);
    if (!res) {
        fprintf(stderr, "Error getting DRM resources: %s\n", strerror(errno));
        close(fd);
        return 1;
    }
    for (i = 0; i < res->count_connectors; i++) {
        conn = drmModeGetConnector(fd, res->connectors[i]);
        if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes > 0) {
            connector_id = conn->connector_id;
            mode = conn->modes[0];
            drmModeFreeConnector(conn);
            break;
        }
        drmModeFreeConnector(conn);
    }
    if (i == res->count_connectors) {
        fprintf(stderr, "Error: no connected connector with modes found.\n");
        drmModeFreeResources(res);
        close(fd);
        return 1;
    }

    // Find the encoder for the chosen connector
    enc = drmModeGetEncoder(fd, conn->encoder_id);
    if (!enc) {
        fprintf(stderr, "Error getting DRM encoder: %s\n", strerror(errno));
        drmModeFreeResources(res);
        close(fd);
        return 1;
    }
    encoder_id = enc->encoder_id;
    drmModeFreeEncoder(enc);

    // Find the CRTC that is driving the encoder
    for (i = 0; i < res->count_crtcs; i++) {
        crtc = drmModeGetCrtc(fd, res->crtcs[i]);
        if (crtc->crtc_id == enc->crtc_id) {
            crtc_id = crtc->crtc_id;
            drmModeFreeCrtc(crtc);
            break;
        }
        drmModeFreeCrtc(crtc);
    }
    if (i == res->count_crtcs) {
        fprintf(stderr, "Error: no CRTC found for encoder.\n");
        drmModeFreeResources(res);
        close(fd);
        return 1;
    }

    // Allocate memory for the image buffer
    image_size = BUFFER_SIZE;
    image_buffer = (uint32_t *)mmap(NULL, image_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_32BIT, fd, 0);
    if (image_buffer == MAP_FAILED) {
        fprintf(stderr, "Error mapping image buffer: %s\n", strerror(errno));
        drmModeFreeResources(res);
        close(fd);
        return 1;
    }
    image_pitch = mode.hdisplay * 4;

    // Initialize the image buffer with some data
    for (i = 0; i < mode.hdisplay * mode.vdisplay; i++) {
        image_buffer[i] = 0xFF0000FF; // red
    }

    // Set the CRTC mode and enable it
    ret = drmModeSetCrtc(fd, crtc_id, 0, 0, connector_id, &encoder_id, 1, &mode);
    if (ret) {
        fprintf(stderr, "Error setting DRM CRTC: %s\n", strerror(errno));
        munmap(image_buffer, image_size);
        drmModeFreeResources(res);
        close(fd);
        return 1;
    }

    // Use page flipping to display the image buffer
    ret = drmModePageFlip(fd, crtc_id, 0, DRM_MODE_PAGE_FLIP_EVENT, &image_buffer);
    if (ret) {
        fprintf(stderr, "Error flipping DRM page: %s\n", strerror(errno));
        munmap(image_buffer, image_size);
        drmModeFreeResources(res);
        close(fd);
        return 1;
    }

    // Wait for VBlank event
    drmEventContext evctx;
    evctx.version = DRM_EVENT_CONTEXT_VERSION;
    evctx.page_flip_handler = NULL;
    evctx.vblank_handler = NULL;

    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(fd, &fds);

    while (true) {
        ret = select(fd + 1, &fds, NULL, NULL, NULL);
        if (ret < 0) {
            fprintf(stderr, "Error waiting for VBlank event: %s\n", strerror(errno));
            drmModeFreeCrtc(crtc);
            drmModeFreeEncoder(enc);
            drmModeFreeConnector(conn);
            drmModeFreeResources(res);
            close(fd);
            return 1;
        }

        drmEventContext event = evctx;
        drmHandleEvent(fd, &event);
    }
    return 0;
}
